package com.xpec.c4.codec.marshalling;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;

import org.infinispan.marshall.jboss.JBossMarshaller;
import org.jboss.marshalling.ByteBufferInput;
import org.jboss.marshalling.Marshaller;
import org.jboss.marshalling.MarshallerFactory;
import org.jboss.marshalling.Marshalling;
import org.jboss.marshalling.MarshallingConfiguration;
import org.jboss.marshalling.Unmarshaller;

import com.xpec.c4.codec.Codec;
import com.xpec.c4.service.group.transportlayer.GroupMember;

/**
 * 用户server间的消息序列化
 * 
 * @author Helo Yi
 *
 */
public class MarshallingCodec implements Codec {

	private JBossMarshaller marshaller = new JBossMarshaller();

	@Override
	public ByteBuffer encode(Object obj) throws Exception {
		byte[] bytes = encodeByte(obj);

		ByteBuffer buffer = ByteBuffer.allocate(bytes.length);
		buffer.put(bytes);
		buffer.flip();

		return buffer;
	}

	@Override
	public byte[] encodeEx(Object obj) throws Exception {
		return encodeByte(obj);
	}

	@Override
	public Object decode(ByteBuffer byteBuffer) throws Exception {
//		Unmarshaller unmarshaller = factory.createUnmarshaller(configuration);
//		
//		ByteBufferInput input = new ByteBufferInput(byteBuffer);
//		
//		unmarshaller.start(input);
//		Object obj = unmarshaller.readObject();
//		unmarshaller.finish();
		
//		return obj;
		
		return decodeByte(byteBuffer.array());
	}

	@Override
	public byte[] encodeByte(Object obj) throws Exception {
//		Marshaller marshaller = factory.createMarshaller(configuration);
		
//		ByteArrayOutputStream out = new ByteArrayOutputStream();
//		
//		marshaller.start(Marshalling.createByteOutput(out));
//		marshaller.writeObject(obj);
//		marshaller.finish();

//		return out.toByteArray();
		
		return marshaller.objectToByteBuffer(obj);
	}

	@Override
	public Object decodeByte(byte[] byteBuffer) throws Exception {
//		return decode(ByteBuffer.wrap(byteBuffer));
		
		return marshaller.objectFromByteBuffer(byteBuffer);
	}

	public static void main(String[] args) throws Exception {
//		byte[] b = testOutput("hello world");
//		System.out.println("bytes: " + b);
//		Object obj = testInput(b);
//		System.out.println("obj: " + obj);
		
		System.gc();
		long beforeMemory = Runtime.getRuntime().freeMemory();
		
		
		for (int i = 0; i < 1; i++) {
			MarshallingCodec codec = new MarshallingCodec();
			
			GroupMember gm = new GroupMember();
			gm.setAddress("server04_transport");
			gm.setLoginTime(System.currentTimeMillis());
			gm.setServerName("server04");
			gm.getServiceModule().add("instancemanager_00101");
			gm.getServiceModule().add("instancemanager_00102");
			gm.getServiceModule().add("instancemanager_00201");
			gm.getServiceModule().add("instancemanager_gem_00");
			gm.getServiceModule().add("instancemanager_gem_01");
			gm.getServiceModule().add("instancemanager_gem_02");
			gm.getServiceModule().add("instancemanager_gem_03");
			gm.getServiceModule().add("instancemanager_gem_04");
			gm.getServiceModule().add("instancemanager_gem_05");
			gm.getServiceModule().add("instancemanager_pet_00");
			gm.getServiceModule().add("instancemanager_res_00");
			gm.getServiceModule().add("instancemanager_test_00");
			gm.getServiceModule().add("instancemanager_test_01");
			gm.getServiceModule().add("instancemanager_test_02");
			gm.getServiceModule().add("instancemanager_test_03");
			gm.getServiceModule().add("instancemanager_test_04");
			for (int j = 0; j < 5000; j++) {
				gm.getServiceModule().add("instancemanager_testa_" + j);
			}
			
			byte[] b = codec.encodeByte(gm);
			System.out.println("b size:"+b.length);
			GroupMember n = (GroupMember)codec.decodeByte(b);
			
			String so = gm.getServiceModule().toString();
			String sn = n.getServiceModule().toString();
			
			System.out.println(so.equals(sn));
		}
		
		System.gc();
		long afterMemory = Runtime.getRuntime().freeMemory();
		
		System.out.println("totalMemory:"+Runtime.getRuntime().totalMemory());
		System.out.println("beforeMemory:"+beforeMemory);
		System.out.println("afterMemory:"+afterMemory);
		System.out.println("used Memory:"+(beforeMemory - afterMemory));
		
//		b = codec.encodeByte(gm.getServiceModule());
//		List l = (List)codec.decodeByte(b);
//		System.out.println("old:"+gm.getServiceModule());
//		System.out.println("new:"+l);
//		
//		
//		
//		System.out.println("bytes: " + b);
//		Object obj = testInput(b);
//		System.out.println("obj: " + obj);
		
		
	}

	private static Object testInput(byte[] bytes) {
		// Get the factory for the "river" marshalling protocol
		final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("river");

		// Create a configuration
		final MarshallingConfiguration configuration = new MarshallingConfiguration();

		try {
			final Unmarshaller unmarshaller = marshallerFactory.createUnmarshaller(configuration);
			// final FileInputStream is = new FileInputStream(args[0]);
			// MarshallingInput input = new MarshallingInput(bytes);
			ByteBuffer buffer = ByteBuffer.wrap(bytes);
			ByteBufferInput input = new ByteBufferInput(buffer);
			try {
				// unmarshaller.start(Marshalling.createByteInput(is));
				unmarshaller.start(input);
				Object obj = unmarshaller.readObject();
				// System.out.println("Read object: " +
				// unmarshaller.readObject());
				unmarshaller.finish();
				// is.close();
				return obj;
			} finally {
				// clean up stream resource
				// try {
				// is.close();
				// } catch (IOException e) {
				// System.err.print("Stream close failed: ");
				// e.printStackTrace();
				// }
			}
		} catch (IOException e) {
			System.err.print("Marshalling failed: ");
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			System.err.print("Marshalling failed: ");
			e.printStackTrace();
		}

		return null;
	}

	private static byte[] testOutput(Object obj) {
		// output
		// String file = "d:/test";
		// Object obj = "hello world";

		// Get the factory for the "river" marshalling protocol
		final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("river");

		// Create a configuration
		final MarshallingConfiguration configuration = new MarshallingConfiguration();
		// Use version 3
		configuration.setVersion(3);
		try {
			final Marshaller marshaller = marshallerFactory.createMarshaller(configuration);
			// final FileOutputStream os = new FileOutputStream(file);
			// MarshallingOutput out = new MarshallingOutput();
			// ByteBuffer buffer = ByteBuffer.allocate(1024);
			// ByteBufferOutput out =new ByteBufferOutput(buffer);
			ByteArrayOutputStream out = new ByteArrayOutputStream();
			try {
				// marshaller.start(Marshalling.createByteOutput(os));
				marshaller.start(Marshalling.createByteOutput(out));
				// marshaller.start(out);
				marshaller.writeObject(obj);
				marshaller.finish();

				return out.toByteArray();
				// os.close();
			} finally {
				// clean up stream resource
				// try {
				// os.close();
				// } catch (IOException e) {
				// System.err.print("Stream close failed: ");
				// e.printStackTrace();
				// }
			}
		} catch (IOException e) {
			System.err.print("Marshalling failed: ");
			e.printStackTrace();
		}
		return null;
	}
}
